package com.s7.widget.recycler.adapter;

import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.s7.widget.R;
import com.s7.widget.recycler.RecyclerCode;
import com.s7.widget.recycler.holder.BaseHolder;
import com.s7.widget.recycler.holder.BaseViewHolder;
import com.s7.widget.recycler.holder.ErrorViewHolder;
import com.s7.widget.recycler.holder.LoadErrorHolder;
import com.s7.widget.recycler.holder.LoadViewHolder;
import com.s7.widget.recycler.listener.Recycler;

import java.util.List;

public abstract class BaseLoadAdapter<T> extends CompatRecyclerAdapter<T> {

    @NonNull
    @Override
    public BaseHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == RecyclerCode.TYPE_ITEM) {
            View view = getView(parent, getLayoutId());
            return new BaseViewHolder<>(view);
        } else if (viewType == RecyclerCode.TYPE_LOAD) {
            View view = getView(parent, getLoadId());
            return new LoadViewHolder(view);
        } else {
            View view = getView(parent, getLoadErrorId());
            return new LoadErrorHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull BaseHolder holder, int position) {

        holder.setRealPosition(position);

        initListener(holder);

        if (holder instanceof BaseViewHolder) {
            initClickListener((BaseViewHolder) holder, datas.get(position));
            ((BaseViewHolder) holder).setData(datas.get(position));
            bindData((BaseViewHolder) holder, position, datas.get(position));
        }

        if (holder instanceof LoadViewHolder) {
            bindLoad((LoadViewHolder) holder, position);
        }

        if (holder instanceof LoadErrorHolder) {
            bindLoadError((LoadErrorHolder) holder, position);
        }
    }

    @Override
    public int getItemCount() {
        if (isLegal() && !isFirst) {
            return datas == null ? 1 : datas.size() + 1;
        }
        return datas == null ? 0 : datas.size();
    }

    public boolean isLegal() {
        if (isLoad) return true;
        if (isLoadError) return true;
        return false;
    }

    @Override
    public int getItemViewType(int position) {

        if (isLoad && position + 1 == getItemCount()) {
            return RecyclerCode.TYPE_LOAD;
        }

        if (isLoadError && position + 1 == getItemCount()) {
            return RecyclerCode.TYPE_LOAD_ERROR;
        }

        return RecyclerCode.TYPE_ITEM;
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return isLast(position) ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(@NonNull BaseHolder holder) {
        super.onViewAttachedToWindow(holder);
        if (isStaggeredGridLayout(holder)) {
            handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
        }
    }

    private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
        if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
            return true;
        }
        return false;
    }

    private void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
        if (isLast(position)){
            ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            ((StaggeredGridLayoutManager.LayoutParams) layoutParams).setFullSpan(true);
        }
    }

    private boolean isLast(int position) {
        if (isAadditional) {
            if (datas == null) {
                return true;
            }

            if (datas.size() == 0) {
                return true;
            }
            return false;
        }
        return false;
    }

    protected abstract int getLayoutId();

    protected int getLoadId() {
        return R.layout.recycler_load;
    }

    protected int getLoadErrorId() {
        return R.layout.recycler_load_error;
    }

    protected abstract void bindData(BaseViewHolder holder, int position, T data);

    protected void bindLoadError(LoadErrorHolder holder, int position) {

    }

    protected void bindLoad(LoadViewHolder holder, int position) {

    }

    private boolean isFirst = true;
    private boolean isAadditional = true;
    private boolean isLoad = true;
    private boolean isLoadError = false;
    private Recycler.OnLoadingListener loadingListener;

    public BaseLoadAdapter setAadditional(boolean aadditional) {
        isAadditional = aadditional;
        return this;
    }

    public BaseLoadAdapter setLoad(boolean load) {
        if (isAadditional) {
            isLoad = load;
        } else {
            isLoad = false;
        }
        return this;
    }

    public BaseLoadAdapter setLoadError(boolean loadError) {
        if (isAadditional) {
            isLoadError = loadError;
            isLoad = !isLoadError;
        } else {
            isLoadError = false;
            isLoad = false;
        }
        notifyDataSetChanged();

        return this;
    }

    public BaseLoadAdapter setLoadingListener(Recycler.OnLoadingListener loadingListener) {
        this.loadingListener = loadingListener;
        return this;
    }

    protected void initListener(final BaseHolder holder) {

        if (holder instanceof LoadErrorHolder) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    setLoadError(false);
                }
            });
        }

        if (holder instanceof LoadViewHolder) {
            if (loadingListener != null) {
                loadingListener.onLoading();
            }
        }

        if (holder instanceof ErrorViewHolder) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (loadingListener != null) {
                        loadingListener.onReload();
                    }
                }
            });
        }
    }

    public void onRefresh(List<T> datas) {
        initFlag();
        initData();
        this.datas.clear();
        if (datas != null) {
            this.datas.addAll(datas);
        }
        notifyDataSetChanged();
    }

    private void initFlag() {
        isFirst = false;
        if (isAadditional) {
            isLoadError = false;
            isLoad = true;
        } else {
            isLoadError = false;
            isLoad = false;
        }
    }

}
